using System;
using System.Collections.Generic;
using System.Reflection;
using System.Web.Mvc;
using Rhino.Commons;
using Rhino.Security.Interfaces;
using WineCellar.Business.ServiceInterfaces;
using WineCellar.Web.Security;

namespace WineCellar.Web.Controllers
{
    public class PermissionController :Controller
    {
        private static readonly List<string> Operations = GetAllOperations();
        private readonly IAuthorizationRepository authRepos;
        private readonly IPermissionsBuilderService permissionsBuilderService;
        private readonly IUserService userService;

        public PermissionController(IAuthorizationRepository authRepos, IPermissionsBuilderService permissionsBuilderService,IUserService userService)
        {
            this.authRepos = authRepos;
            this.permissionsBuilderService = permissionsBuilderService;
            this.userService = userService;
        }

        public ActionResult Manage()
        {
            ViewData["Operations"] = Operations;
            //ViewData["UserGroups"] = authRepos.;
            return View();
        }

        private static List<string> GetAllOperations()
        {
            var ret = new List<string>();

            foreach (Assembly a in System.Web.Compilation.BuildManager.GetReferencedAssemblies())
            {
                foreach (Type controllerType in a.GetTypes())
                {
                    if ((typeof(Controller).IsAssignableFrom(controllerType)) && !controllerType.IsAbstract)
                    {
                        foreach (var method in controllerType.GetMethods())
                        {
                            if ((typeof(ActionResult).IsAssignableFrom(method.ReturnType)) && !method.IsDefined(typeof(NonActionAttribute), true))
                            {
                                var actionName = method.IsDefined(typeof(SecuredOperationAttribute), true)
                                    ? ((SecuredOperationAttribute)method.GetCustomAttributes(typeof(SecuredOperationAttribute), true)[0]).Name
                                    : method.Name;

                                var operation = string.Format("/{0}/{1}", controllerType.Name, actionName);

                                if (!ret.Contains(operation))
                                    ret.Add(operation);
                            }
                        }
                    }
                }
            }

            return ret;
        }

        public ActionResult Generate()
        {
            using (UnitOfWork.Start())
            {
                var userGroup = authRepos.GetUsersGroupByName("developers");
                if (userGroup == null)
                {
                    userGroup = authRepos.CreateUsersGroup("developers");
                    UnitOfWork.Current.TransactionalFlush();
                }

                var user = userService.GetUser("bart");
                authRepos.AssociateUserWith(user, userGroup);
                UnitOfWork.Current.TransactionalFlush();

                //if (authRepos.GetOperationByName("/") == null)
                //{
                //    authRepos.CreateOperation("/");
                //    UnitOfWork.Current.TransactionalFlush();
                //}

                foreach (var operation in Operations)
                {
                    if (authRepos.GetOperationByName(operation) != null) continue;

                    authRepos.CreateOperation(operation);
                    UnitOfWork.Current.TransactionalFlush();
                }

                foreach (var operation in Operations)
                {
                    permissionsBuilderService
                        .Allow(operation)
                        .For(userGroup)
                        .OnEverything()
                        .Level(10)
                        .Save();

                    UnitOfWork.Current.TransactionalFlush();


                }

                UnitOfWork.Current.TransactionalFlush();

                return View();
            }
        }
    }
}